package com.zdxlz.fcmp.upms.api.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zdxlz.fcmp.common.core.exception.BizException;
import com.zdxlz.fcmp.upms.api.dto.SystemRoleDto;
import com.zdxlz.fcmp.upms.api.entity.SystemMenu;
import com.zdxlz.fcmp.upms.api.entity.SystemRole;
import com.zdxlz.fcmp.upms.api.entity.SystemRoleMenu;
import com.zdxlz.fcmp.upms.api.entity.SystemUserRole;
import com.zdxlz.fcmp.upms.api.mapper.SystemMenuMapper;
import com.zdxlz.fcmp.upms.api.mapper.SystemRoleMapper;
import com.zdxlz.fcmp.upms.api.mapper.SystemRoleMenuMapper;
import com.zdxlz.fcmp.upms.api.mapper.SystemUserRoleMapper;
import com.zdxlz.fcmp.upms.api.service.ISystemRoleService;
import com.zdxlz.fcmp.upms.api.vo.SystemRoleVo;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.zdxlz.fcmp.common.core.constant.CommonConstants.ROLE_ID;
import static com.zdxlz.fcmp.common.core.constant.enums.ResCode.*;

/**
 * 角色信息表(SystemRole)表服务实现类
 *
 * @author makejava
 * @since 2025-02-24 13:49:10
 */
@Service
public class SystemRoleServiceImpl extends ServiceImpl<SystemRoleMapper, SystemRole> implements ISystemRoleService {

    @Resource
    private SystemUserRoleMapper systemUserRoleMapper;

    @Resource
    private SystemRoleMenuMapper systemRoleMenuMapper;

    @Autowired
    private SystemMenuMapper systemMenuMapper;

    /**
     * 分页查询数据
     */
    @Override
    public IPage<SystemRoleVo> selectSystemRole(Page<SystemRole> page, SystemRoleDto dto) {
        LambdaQueryWrapper<SystemRole> queryWrapper = new LambdaQueryWrapper<>();
        if (ObjectUtil.isNotEmpty(dto)) {
            queryWrapper
                    .eq(SystemRole::getTenantId, dto.getTenantId())
                    .like(StrUtil.isNotBlank(dto.getName()), SystemRole::getName, dto.getName())
                    .like(StrUtil.isNotBlank(dto.getCode()), SystemRole::getCode, dto.getCode())
                    .eq(ObjectUtil.isNotEmpty(dto.getStatus()), SystemRole::getStatus, dto.getStatus());
        }
        Page<SystemRole> systemRolePage = baseMapper.selectPage(page, queryWrapper);

        List<SystemRoleVo> systemRoleVos = systemRolePage.getRecords().stream().map(this::convertToSystemRoleVo).collect(Collectors.toList());
        IPage<SystemRoleVo> roleVoPage = new Page<>(systemRolePage.getCurrent(), systemRolePage.getSize(), systemRolePage.getTotal());
        roleVoPage.setRecords(systemRoleVos);
        return roleVoPage;
    }

    /**
     * 新增一条数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean insertSystemRole(SystemRoleDto dto) {
        List<SystemRole> roleList = getSystemRoles(dto);
        if (CollectionUtil.isNotEmpty(roleList)) throw new BizException(RULE_CODE_REPEAT.getCode(), RULE_CODE_REPEAT.getReason());

        baseMapper.insert(dto);
        List<Integer> menuIds = dto.getMenuIds();
        if (CollectionUtil.isNotEmpty(menuIds)) {
            verifyMenuIsExist(menuIds);
            systemRoleMenuMapper.insert(buildSystemRoleMenu(dto.getId(), menuIds));
        }
        return true;
    }

    /**
     * 通过ID更新一条数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateSystemRole(SystemRoleDto dto) {
        List<SystemRole> roleList = getSystemRoles(dto);
        List<SystemRole> systemRoles = roleList.stream().filter(role -> !role.getId().equals(dto.getId())).toList();
        if (CollectionUtil.isNotEmpty(systemRoles)) throw new BizException(RULE_CODE_REPEAT.getCode(), RULE_CODE_REPEAT.getReason());

        List<Integer> menuIds = dto.getMenuIds();
        systemRoleMenuMapper.deleteByMap(Map.of(ROLE_ID, dto.getId()));
        if (CollectionUtil.isNotEmpty(menuIds)) {
            verifyMenuIsExist(menuIds);
            systemRoleMenuMapper.insert(buildSystemRoleMenu(dto.getId(), menuIds));
        }
        baseMapper.updateById(dto);
        return true;
    }

    /**
     * @description：通过角色ID删除角色表数据以及角色菜单关系表数据
     * @author：aman
     * @date：2025/2/25 10:40
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteSystemRole(List<Integer> ids) {
        List<SystemRole> collect = baseMapper.selectByIds(ids).stream().filter(menu -> menu.getStatus() == Boolean.TRUE).toList();
        if (CollectionUtil.isNotEmpty(collect)) {
            throw new BizException(ERROR_ROLE_QY_STATUS.getCode(), ERROR_ROLE_QY_STATUS.getReason());
        }
        if (CollectionUtil.isNotEmpty(systemUserRoleMapper.selectList(new LambdaQueryWrapper<SystemUserRole>().in(SystemUserRole::getRoleId, ids)))) {
            throw new BizException(RULE_BANDED_USER.getCode(), RULE_BANDED_USER.getReason());
        }
        systemRoleMenuMapper.delete(new LambdaQueryWrapper<SystemRoleMenu>().in(SystemRoleMenu::getRoleId, ids));
        baseMapper.deleteByIds(ids, true);
        return true;
    }

    /**
     * @description：校验菜单是否存在
     * @author：aman
     * @date：2025/2/24 15:06
     */
    public void verifyMenuIsExist(List<Integer> menuIds) {
        List<SystemMenu> systemMenus = systemMenuMapper.selectByIds(menuIds);
        if (systemMenus.size() != menuIds.size()) throw new BizException(MENU_NOT_EXIST.getCode(), MENU_NOT_EXIST.getReason());
    }

    /**
     * @description：通过租户id、角色名称、编号获取角色信息
     * @author：aman
     * @date：2025/2/28 14:40
     */
    private List<SystemRole> getSystemRoles(SystemRoleDto dto) {
        return baseMapper.selectList(new LambdaQueryWrapper<SystemRole>()
                .eq(SystemRole::getTenantId, dto.getTenantId())
                .eq(SystemRole::getCode, dto.getCode())
                .or()
                .eq(SystemRole::getName, dto.getName()));
    }

    /**
     * @description：构建角色菜单集合信息
     * @author：aman
     * @date：2025/2/24 15:06
     */
    private static List<SystemRoleMenu> buildSystemRoleMenu(Integer roleId, List<Integer> menuIds) {
        List<SystemRoleMenu> systemRoleMenus = new ArrayList<>();
        menuIds.forEach(menuId -> {
            SystemRoleMenu systemRoleMenu = new SystemRoleMenu();
            systemRoleMenu.setRoleId(roleId);
            systemRoleMenu.setMenuId(menuId);
            systemRoleMenus.add(systemRoleMenu);
        });
        return systemRoleMenus;
    }

    private SystemRoleVo convertToSystemRoleVo(SystemRole systemRole) {
        SystemRoleVo systemRoleVo = new SystemRoleVo();
        BeanUtil.copyProperties(systemRole, systemRoleVo);
        List<SystemRoleMenu> systemRoleMenus = systemRoleMenuMapper.selectList(new LambdaQueryWrapper<SystemRoleMenu>().eq(SystemRoleMenu::getRoleId, systemRole.getId()));
        List<Integer> list = systemRoleMenus.stream().map(SystemRoleMenu::getMenuId).toList();
        systemRoleVo.setMenuIds(list);
        return systemRoleVo;
    }
}
